/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * The Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
 *
 * The Initial Developer of the Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
 * Portions created by Mark A. Kobold are Copyright (C) 2000-2007. All Rights Reserved.
 *
 * Contributor(s): 
 *  Mark A. Kobold [mkobold <at> isqlviewer <dot> com].
 *  
 * If you didn't download this code from the following link, you should check
 * if you aren't using an obsolete version: http://www.isqlviewer.com
 */
package org.isqlviewer.model;

import java.sql.SQLException;
import java.util.Vector;

import javax.swing.tree.TreePath;

import org.isqlviewer.swing.outline.AbstractTreeTableModel;
import org.isqlviewer.swing.outline.OutlineModel;
import org.isqlviewer.util.LocalMessages;

/**
 * Outline model for showing exceptions in a tree-table fashion.
 * <p>
 * 
 * @author Mark A. Kobold &lt;mkobold at isqlviewer dot com&gt;
 * @version 1.0
 */
public class ThrowableOutlineModel extends AbstractTreeTableModel {

    private static final Class[] columnTypes = {OutlineModel.class, String.class, String.class};
    private static final String RESOURCE_BUNDLE = "org.isqlviewer.model.ResourceBundle";

    private Object root = new Object();
    private LocalMessages messages = new LocalMessages(RESOURCE_BUNDLE);
    private Vector<Throwable> errorChain = new Vector<Throwable>();

    public ThrowableOutlineModel(Throwable error) {

        errorChain.add(error);
        Throwable sourceError = error;
        Throwable nextError = getCause(sourceError);
        while (nextError != null && nextError != sourceError) {
            errorChain.add(nextError);
            sourceError = nextError;
            nextError = getCause(sourceError);
        }
    }

    public Class getColumnClass(int column) {

        return columnTypes[column];
    }

    public int getColumnCount() {

        return columnTypes.length;
    }

    public String getColumnName(int column) {

        switch (column) {
            case 0 :
                return messages.format("ThrowableOutlineModel.stacktrace_column.header");
            case 1 :
                return messages.format("ThrowableOutlineModel.sqlstate_column.header");
            case 2 :
                return messages.format("ThrowableOutlineModel.sqlerror_column.header");
            default :
                return null;
        }
    }

    public Object getValueAt(Object node, int column) {

        if (node instanceof SQLException) {
            SQLException sqlError = (SQLException) node;
            switch (column) {
                case 1 :
                    return sqlError.getSQLState();
                case 2 :
                    return Integer.toString(sqlError.getErrorCode());
            }
        } else {
            switch (column) {
                case 1 :
                    return "";
                case 2 :
                    return "";
            }
        }
        return node;
    }

    public Object getChild(Object parent, int index) {

        if (parent == root) {
            return errorChain.elementAt(index);
        } else if (parent instanceof Throwable) {
            return ((Throwable) parent).getStackTrace()[index];
        }
        return null;
    }

    public int getChildCount(Object parent) {

        if (parent == root) {
            return errorChain.size();
        } else if (parent instanceof Throwable) {
            return ((Throwable) parent).getStackTrace().length;
        }
        return 0;
    }

    public int getIndexOfChild(Object parent, Object child) {

        if (parent == root) {
            return errorChain.indexOf(child);
        } else if (parent instanceof Throwable) {
            StackTraceElement[] stackTrace = ((Throwable) parent).getStackTrace();
            for (int i = 0; i < stackTrace.length; i++) {
                String line = stackTrace[i].toString();
                if (line.equals(child)) {
                    return i;
                }
            }
        }
        return -1;
    }

    public Object getRoot() {

        return root;
    }

    public boolean isLeaf(Object node) {

        return !(node instanceof Throwable) && node != root;
    }

    public void valueForPathChanged(TreePath path, Object newValue) {

    }

    private Throwable getCause(Throwable sourceError) {

        if (sourceError instanceof SQLException) {
            Throwable cause = ((SQLException) sourceError).getNextException();
            if (cause != null) {
                return cause;
            }
        }
        return sourceError.getCause();
    }
}